package cn.ac.iscas.chinesesegmentme;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

public class Tokenizer {
	private Vector<Vector<Token>> tokenlistSet= new Vector<Vector<Token>>();
	private static final String senStart = "s";
	private static final String senEnd = "/s";
	private static double maxp = 0;
	private static int[] maxtaglist = null;
	private static double[][] maxleft = null;
	private static int[][] indexleft = null;
	private int check = 0;
	
	public void tokenizeTrainLine(String line){
		Vector<Token> tokenlist = new Vector<Token>();
		String[] tmp = line.split("\\|");
		for (int i = 0; i < tmp.length; i++){
			String tmpStr = tmp[i].trim();
			if (tmpStr.length() > 0){
				String[] tmp2 = tmpStr.split(" ");
				if (tmp2.length == 1){
					tokenlist.add(new Token(tmp2[0], Token.Single));
				} else {
					tokenlist.add(new Token(tmp2[0], Token.Begin));
					for (int j = 1; j < tmp2.length - 1; j ++){
						tokenlist.add(new Token(tmp2[j], Token.Middle));
					}
					tokenlist.add(new Token(tmp2[tmp2.length - 1], Token.End));
				}
			}
		}
		tokenlistSet.add(tokenlist);
	}
	
	public void tokenizeTestLine(String line, BufferedReader pbr){
		Vector<Token> tokenlist = new Vector<Token>();
			String tmpStr = line.trim();
			if (tmpStr.length() > 0){
				String[] tmp2 = tmpStr.split(" ");
				for (int j = 0; j < tmp2.length; j ++){
					if (!tmp2[j].equals("")){
						try {
							//tokenlist.add(new Token(tmp2[j], getPredictResult(pbr.readLine())));
							tokenlist.add(new Token(tmp2[j], getPredictResultMaxent(pbr.readLine())));
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
		}
		tokenlistSet.add(tokenlist);	
	}
	
	public void tokenizeTestLine(String line, BufferedReader pbr, BufferedReader pbr2){
		Vector<Token> tokenlist = new Vector<Token>();
			String tmpStr = line.trim();
			if (tmpStr.length() > 0){
				String[] tmp2 = tmpStr.split(" ");
				for (int j = 0; j < tmp2.length; j ++){
					if (!tmp2[j].equals("")){
						try {
							//tokenlist.add(new Token(tmp2[j], getPredictResult(pbr.readLine())));
							tokenlist.add(new Token(tmp2[j], getPredictResultDouble(pbr.readLine(), pbr2.readLine())));
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
		}
		tokenlistSet.add(tokenlist);	
	}
	
	private double[] getPredictResultDouble(String line, String line2){
		//if (line == null) return null;
		boolean flag = true;
		String[] tmp2 = line2.split(" ");
		String[] tmp = line.split("\t");
		double[] result = new double[tmp.length];
		for (int i = 0; i < 4; i++){
			if (Double.parseDouble(tmp2[i]) > 0.422){
				result[i] = Double.parseDouble(tmp2[i]) * 0.065;
				result[i] += Double.parseDouble(tmp[2*i+1]) * 0.935;
			} else {
				result[i] = Double.parseDouble(tmp[2*i+1]);
			}
		}
		return result;
	}
	
	private double[] getPredictResult(String line){
		//if (line == null) return null;
		String[] tmp = line.split(" ");
		double[] result = new double[tmp.length];
		for (int i = 0; i < tmp.length; i++){
			result[i] = Double.parseDouble(tmp[i]);
		}
		return result;
	}
	
	private double[] getPredictResultMaxent(String line){
		//if (line == null) return null;
		String[] tmp = line.split("\t");
		double[] result = new double[tmp.length];
		for (int i = 0; i < 4; i++){
			result[i] = Double.parseDouble(tmp[2*i+1]);
		}
		return result;
	}
	
	public String toString(){
		String result = "";
		for(Iterator it=tokenlistSet.iterator();it.hasNext();)
		{
			Vector<Token> tokenlist = (Vector<Token>) it.next();
			for (int i = 0; i < tokenlist.size(); i++){
				result += tokenlist.get(i) + " ";
			}
			result += "\n";
		}
		return result;
	}
	
	public void generateTrainFile(){
		for(Iterator it=tokenlistSet.iterator();it.hasNext();)
		{
			Vector<Token> tokenlist = (Vector<Token>) it.next();
			for (int i = 0; i < tokenlist.size(); i++){
				String line = "";
				line += getResult(tokenlist, i);
				line += " ";
				line += getFeatureA(tokenlist, i);
				line += getFeatureB(tokenlist, i);
				line += getFeatureC(tokenlist, i);		
				System.out.println(line);
			}
			
		}		
	}
	
	private String getResult(Vector<Token> tokenlist, int pos){
		return tokenlist.get(pos).tag;
	}

	private int judgePosition(int pos, int offset, int length){
		if (pos + offset == -1){
			return 0;
		} else if (pos + offset == length - 1){
			return 3;
		} else if (pos + offset == 0){
			return 1;
		} else if (pos + offset == length){
			return 4;
		} else if (pos + offset > -1 && (pos + offset < length)){
			return 2;
		} else {
			return -1;
		}
	}

	private String getFeatureA(Vector<Token> tokenlist, int pos){
		String result = "";
		for (int i = -2; i <= 2; i++){
			int position = judgePosition(pos, i, tokenlist.size());
			if (position >= 0){
				result += getHead(i);
				switch (position){
				case 0:
					result += getExtendString(senStart);
					break;
				case 1:
				case 2:
				case 3:
					result += getExtendString(tokenlist.get(pos + i).content);
					break;
				case 4:
					result += getExtendString(senEnd);
					break;
				}
				result += getExtendString(tokenlist.get(pos).content);
				result += " ";
			}
		}
		return result;
	}
	
	private String getHead(int pos){
		return "C" + pos + ":";
	}
	
	private String getHead(int pos1, int pos2){
		return "C" + pos1 + "," + pos2+ ":";
	}
	
	private String getFeatureB(Vector<Token> tokenlist, int pos){
		String result = "";
		for (int i = -2; i <= 1; i++){
			int position = judgePosition(pos, i, tokenlist.size());
			if (position >= 0){
				result += getHead(i, i + 1);
				switch (position){
				case 0:
					result += getExtendString(senStart);
					result += getExtendString(tokenlist.get(0).content);
					break;
				case 1:
				case 2:
					result += getExtendString(tokenlist.get(pos + i).content);
					result += getExtendString(tokenlist.get(pos + i + 1).content);
					break;
				case 3:
					result += getExtendString(tokenlist.get(tokenlist.size() - 1).content);
					result += getExtendString(senEnd);
					break;
				case 4:
					break;
				}
				if (position != 4){
					result += getExtendString(tokenlist.get(pos).content);
					result += " ";
				}
			}
		}
		return result;
	}
	
	
	private String getFeatureC(Vector<Token> tokenlist, int pos){
		String result = "";
		int position = judgePosition(pos, 0, tokenlist.size());
		if (tokenlist.size() == 1){
			result += getExtendString(senStart);
			result += getExtendString(senEnd);
			result += " ";
			return result;
		}
		if (position >= 0){
			result += getHead(-1, 1);
			switch (position){
			case 0:
				break;
			case 1:
				result += getExtendString(senStart);
				result += getExtendString(tokenlist.get(1).content);
				break;
			case 2:
				result += getExtendString(tokenlist.get(pos - 1).content);
				result += getExtendString(tokenlist.get(pos + 1).content);
				break;
			case 3:
				result += getExtendString(tokenlist.get(tokenlist.size() - 2).content);
				result += getExtendString(senEnd);
				break;
			case 4:
				break;
			}
			if (position != 4){
				result += getExtendString(tokenlist.get(pos).content);
				result += " ";
			}
		}
		return result;
	}
	
	private String getExtendString(String input){
		return "<" + input + ">";
	}
	
	public void generateResultFile(){
		for(Iterator it=tokenlistSet.iterator();it.hasNext();)
		{
			Vector<Token> tokenlist = (Vector<Token>) it.next();
			if (tokenlist.size() == 0){
				System.out.println();
				continue;
			}
			getPredictLine(tokenlist);
//			String line = tokenlist.get(0).content;
//			for (int i = 1; i < tokenlist.size(); i++){
//				if (tokenlist.get(i).getMostPossibleTag() == Token.Begin || tokenlist.get(i).getMostPossibleTag() == Token.Single) line += " |";
//				line += " " + tokenlist.get(i).content;		
//			}
//			line += " | ";
//			System.out.println(line);
		}			
	}
	
	private void getPredictLine(Vector<Token> tokenlist){
		maxp = -1000000;
		maxtaglist = new int[tokenlist.size()];
		maxleft = new double[tokenlist.size()][4];
		indexleft = new int[tokenlist.size()][4];
		for (int i = 0; i < tokenlist.size(); i++){
			for (int j = 0; j < 4; j++){
				findMaxProbability(i, j, tokenlist);
			}
		}
		
		if (maxleft[maxleft.length - 1][1] > maxleft[maxleft.length - 1][2]){
			maxp = maxleft[maxleft.length - 1][1];
			findMaxPath(maxleft.length - 1, 1);
		} else {
			maxp = maxleft[maxleft.length - 1][2];
			findMaxPath(maxleft.length - 1, 2);
		}
		
		setTaglist(tokenlist);
		printLine(tokenlist);
//		for (int i = 0; i < maxtaglist.length; i++){
//			System.out.print(maxtaglist[i] + " ");
//		}
//		System.out.println(maxp);
	}
	
	
	//B[0.0305]  E[0.2242]  S[0.7453]  M[0.0000]
	private void findMaxProbability(int index, int tag, Vector<Token> tokenlist){
		if (index == 0){
			maxleft[index][tag] = Math.log(tokenlist.get(index).predict[tag] + 0.0001);
			return;
		}
		if (tag == 0){
			if (maxleft[index - 1][1] > maxleft[index - 1][2]){
				maxleft[index][tag] = maxleft[index - 1][1] + Math.log(tokenlist.get(index).predict[tag] + 0.0001);
				indexleft[index][tag] = 1;
			} else {
				maxleft[index][tag] = maxleft[index - 1][2] + Math.log(tokenlist.get(index).predict[tag] + 0.0001);
				indexleft[index][tag] = 2;				
			}
		} else if (tag == 1){
			if (maxleft[index - 1][0] > maxleft[index - 1][3]){
				maxleft[index][tag] = maxleft[index - 1][0] + Math.log(tokenlist.get(index).predict[tag] + 0.0001);
				indexleft[index][tag] = 0;
			} else {
				maxleft[index][tag] = maxleft[index - 1][3] + Math.log(tokenlist.get(index).predict[tag] + 0.0001);
				indexleft[index][tag] = 3;				
			}
		} else if (tag == 2){
			if (maxleft[index - 1][1] > maxleft[index - 1][2]){
				maxleft[index][tag] = maxleft[index - 1][1] + Math.log(tokenlist.get(index).predict[tag] + 0.0001);
				indexleft[index][tag] = 1;
			} else {
				maxleft[index][tag] = maxleft[index - 1][2] + Math.log(tokenlist.get(index).predict[tag] + 0.0001);
				indexleft[index][tag] = 2;				
			}			
		} else if (tag == 3){
			if (maxleft[index - 1][0] > maxleft[index - 1][3]){
				maxleft[index][tag] = maxleft[index - 1][0] + Math.log(tokenlist.get(index).predict[tag] + 0.0001);
				indexleft[index][tag] = 0;
			} else {
				maxleft[index][tag] = maxleft[index - 1][3] + Math.log(tokenlist.get(index).predict[tag] + 0.0001);
				indexleft[index][tag] = 3;				
			}		
		}
	}
	//B[0.0305]  E[0.2242]  S[0.7453]  M[0.0000]
	private void findMaxPath(int index, int tag){
		if (index < 0) return;
		maxtaglist[index] = tag;
		findMaxPath(index - 1, indexleft[index][tag]);
	}
	
	private void setTaglist(Vector<Token> tokenlist){
		for (int i = 0; i < tokenlist.size(); i++){
			tokenlist.get(i).setTag(maxtaglist[i]);
		}
	}
	private void printLine(Vector<Token> tokenlist){
		for (int i = 0; i < tokenlist.size(); i++){
			System.out.print(tokenlist.get(i).content + " ");
			if (tokenlist.get(i).tag == Token.Single || tokenlist.get(i).tag == Token.End){
				System.out.print("| ");
			}
		}
		System.out.println();
		//System.out.println(" | ");
	}
}
